//
//  httpserver.cpp
//  myhttpserver
//
//  Created by tgy on 2018/3/16.
//  Copyright © 2018年 tgy. All rights reserved.
//

#include "Httpserver.hpp"
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <iostream>

#include <sstream>
#include "Utils.hpp"
#include "ResourceTool.hpp"

#define HTTPSERVERLISTEN 128

Httpserver::Httpserver(){
    
    init();
}


Httpserver::~Httpserver(){
    
    
}

void Httpserver::init(){
    
    this->basePath = "./file";
    this->errorBasePath = "./error/";
    this->error404FilePath = "404.html";
    this->error500FilePath = "500.html";
}

void Httpserver::updateEvent(int ident,short filter,u_short flags,u_int fflags,int data,void *udata){
    
    struct kevent ke;
    
    EV_SET(&ke, ident, filter, flags, fflags, data, udata);
    //设置到
    kevent(kqueueId, &ke, 1, NULL, 0, NULL);
}

void Httpserver::acceptAction(){
    
    
    struct sockaddr_in new_sin;
    bzero(&new_sin, sizeof(new_sin));
    socklen_t st = sizeof(new_sin);
    int new_fd = accept(sockfd, (struct sockaddr *)&new_sin, &st);
    
    if (new_fd < 0) {
        
        perror("accept error");
        return;
    }else{
        
        
        updateEvent(new_fd, EVFILT_READ, EV_ADD| EV_ENABLE, 0, 0, NULL);
        updateEvent(new_fd, EVFILT_WRITE, EV_ADD|EV_DISABLE, 0, 0, NULL);
        
        Client *client = new Client(new_fd,new_sin);
        //保存客户端
        clients.insert(std::pair<int, Client *>(new_fd,client));
        Utils::setNoBlock(new_fd);
        
        std::cout << "链接客户端:"<<client->getClientIP() << ",端口:"<<  client->getClientPort() << std::endl;
    }
    
}

//读操作
void Httpserver::readAction(struct kevent ev){
 
    int read_len = (int)ev.data;
    
    if (read_len == 0) {
        
        read_len = 100;
    }
    
    char *conten = new char[read_len];
    bzero(conten, read_len);
    
    ssize_t len = recv((int)ev.ident, conten, read_len, 0);
    
    if (len == 0) {  //客户端断开了，也断开
        
        disconnectAction(ev);
        
    }else if (len < 0){
        
        perror("recv error");
        //服务器错误
//        disconnectAction(ev);
        
    }else{
        

        Client *client = getClientByFd((int)ev.ident);
        
        if (client != NULL) {
            
            serverHander(conten,client);
        }else{
            
            //服务器错误
            
        }
    }
    
    delete [] conten;
}
//写操作
bool Httpserver::writeAction(struct kevent ev){
    
  
    
    Client *client = getClientByFd((int)ev.ident);
    if (client == NULL) {
      char  *write_err = "HTTP/1.1 404 err\r\nContent-Length: 126\r\nContent-Type: \r\nDate: Fri, 16 Mar 2018 07:39:39 GMT\r\nServer: httpserver/1.0\r\n\r\n";
        send((int)ev.ident, write_err, sizeof(write_err), 0);
        return true;
    }
    
    int write_len = (int)ev.data;
    SendMessageItem *item = client->fontSendItem();

    if (item != NULL && item->getConten() != NULL) {
        
        
        int sendLength = 0;
        int willSendLength = item->getLen() - item->getSendCurrent();
        if (willSendLength > write_len) {
            
            sendLength = write_len;
        }else{
            
            sendLength = willSendLength;
        }
        
        ssize_t send_num =  send((int)ev.ident,item->getConten() + item->getSendCurrent(), sendLength, 0);
        if (send_num != sendLength) {
            
            perror("send error");
            return true;
        }else{
            
            item->setSendCurrent(item->getSendCurrent() + send_num);
            
            if (item->getLen() <= item->getSendCurrent()) {  //当前节点发送完成
                
                client->popSendItem();
                delete item;
                if (client->fontSendItem() == NULL) {  //所以数据发送完成
                    
                    return true;
                }else{
                    
                    return false;
                }
                
            }else{
                return false;
            }
        }
        
    }

 
    return true;
}

//断开连接
void Httpserver::disconnectAction(struct kevent ev){
    
    
    updateEvent((int)ev.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL);
    updateEvent((int)ev.ident, EVFILT_WRITE,  EV_DELETE, 0, 0, NULL);
    
    
    close((int)ev.ident);
    
    std::map<int, Client *>::iterator findResult = clients.find((int)ev.ident);
    if (findResult->second != NULL) {
        
        clients.erase(findResult);
        delete  findResult->second;
    }
    
}


bool Httpserver::start(int port){
    
    this->port = port;
    canRun = false;
    //创建sock
    this->sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        
        perror("socket error");
        return false;
    }
    bzero(&serverSockAddr, sizeof(serverSockAddr));
    
    serverSockAddr.sin_family = PF_INET;
    serverSockAddr.sin_port = htons(port);
    serverSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    if (bind(sockfd, (struct sockaddr *)&serverSockAddr, sizeof(serverSockAddr)) < 0) {
        
        perror("bind error");
        return false;
    }
    
    if (listen(sockfd, HTTPSERVERLISTEN) != 0) {
        
        perror("listen error");
        return false;
    }
    
    Utils::setNoBlock(sockfd);
    
    kqueueId =  kqueue();
    
    updateEvent(sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
    
    canRun = true;
    return true;
}

void  Httpserver::run(){
    
    while (canRun) {
        
        std::cout << "服务器开启，端口号:" << port << std::endl;
        int n = kevent(kqueueId, NULL, 0, evlist, MAXEVENTLEN, NULL);
        
        if (n < 0) {
            
            perror("kevent error");
            continue;
        }
        
        if (n == 0) {
            
            continue;
        }
        
        for (int i = 0; i < n; i++) {
            
            struct kevent temp = evlist[i];
            
            if (temp.ident == sockfd) {
                
                //accept
                acceptAction();
            }else{
                
                if (temp.flags & EV_EOF) {
                    
                    disconnectAction(temp);
                    continue;
                }
                
                if (temp.filter == EVFILT_READ) {
                    
                    readAction(temp);
                    
                    updateEvent((int)temp.ident, EVFILT_READ, EV_DISABLE, 0, 0, NULL);
                    updateEvent((int)temp.ident, EVFILT_WRITE, EV_ENABLE, 0, 0, NULL);
                }else if (temp.filter == EVFILT_WRITE){
                    
                    if (writeAction(temp)) {
                        
                        updateEvent((int)temp.ident, EVFILT_READ, EV_ENABLE, 0, 0, NULL);
                        updateEvent((int)temp.ident, EVFILT_WRITE,  EV_DISABLE, 0, 0, NULL);
                    }
                }
                
            }
            
        }
        
    }
    
}


Client * Httpserver::getClientByFd(int fd){
    
    std::map<int, Client *>::iterator findResult = clients.find(fd);
    Client *client = findResult->second;
    return client;
}

void Httpserver::serverHander(char *content, Client *client){
    
    
    HttpServerRequest  *request = new HttpServerRequest(content);
    HttpserverResponse *response = new HttpserverResponse();
    if (request->parse()) {
        
        
        switch (request->getMethod()) {
            case GET:
                
                getHander(request, response);
                break;
            case POST:
                postHander(request,response);
                break;
            case PUT:
                
                break;
            case DELETE:
                
                break;
            default:
                break;
        }
        
    }else{
        
        //http格式错误
        serverErrorHander(request, response);
    }
    
    std::string sendData = response->getSendMessage();
    
    SendMessageItem *item = new SendMessageItem(sendData.c_str(),sendData.size());
    
    client->pushSendItem(item);
    
    delete request;
    delete response;
    
}

void Httpserver::dispatchMethod(){
    
}

void Httpserver::getHander(HttpServerRequest *request, HttpserverResponse *response){
    
    ResourceTool resourceTool(basePath,request->getPath());
    
    //全路径
    std::string allPath = basePath + request->getPath();
    std::cout << "全路径:"<< allPath<< std::endl;
    Resource *resource = resourceTool.readServer();

    //没读到数据，报404错误
    if (resource == NULL) {
        
        response->setStauts(NOT_FOUND);
        response->setMessage("Not Found");
        
        resourceTool.setBasePath(errorBasePath);
        resourceTool.setRelativePath(error404FilePath);
        resource = resourceTool.readServer();
    }else{
        
        response->setStauts(OK);
        response->setMessage("OK");
    }
    //Content-Type:

//    response->addHeader("content-type", "text/html;charset=UTF8");
    response->addHeader("server", "tgy");
    std::ostringstream oss;
    oss << resource->getLen();
    response->addHeader("content-length", oss.str());
    response->setBody(resource->getData());
    
    delete resource;
}


void Httpserver::postHander(HttpServerRequest *request, HttpserverResponse *response){

   
    
    
}


void Httpserver::serverErrorHander(HttpServerRequest *request, HttpserverResponse *response){
    
    char buf[] = "protocol erro";
    char *data = new char[strlen(buf)];
    bzero(data, strlen(buf));
    strcpy(data, buf);
    Resource resource(data,(int)strlen(buf));
    response->setStauts(BAD_REQUEST);
    response->setMessage("protocal erro");
    
    response->addHeader("server", "tgy");
    std::ostringstream oss;
    oss << resource.getLen();
    response->addHeader("content-length", oss.str());
    response->setBody(resource.getData());
}
























